/* 创建一个Duo的实例对象 */
function createDuo(_duo) {
    return new DuoBase(_duo);
}

/* Duo框架工具类 */
class DuoUtils {
    static getDOM(_str, _startDOMStr = "document") {
        return this.hasDOM(_startDOMStr) ? _startDOMStr.querySelector(_str) : document.querySelector(_str);
    }
    static typeOfPlus(_any) {
        return Object.prototype.toString.call(_any).slice(8, -1);
    }
    static hasDOM(_DOMStr) {
        return /HTML/.test(this.typeOfPlus(document.querySelector(_DOMStr)));
    }
    /* 把两个空格转换为一个空格 */
    static DuoReplaceDoubelSpace(_str = '') {
        return _str.trim().replace("  ", " ");
    }
}

/* Duo框架核心类 */
class DuoBase {
    constructor(_duo = {}) {
        Object.keys(_duo).forEach(_item => {
            this[_item] = _duo[_item] || null;
        })
    }
    /* 数据存储 */
    DuoVDOMTree = [];
    DuoVDOMFraments = null;
    /* 观察者 */
    DuoObsevers = [];
    /* 订阅者 */
    DuoSubscribe = [];
    /* 事件存储 */
    DuoActions = [];
    /* 事件类型存储 */
    DuoActionTypes = new Set();
    /* data解析 */
    handlerData(__innerHtml) {
        let finallyHtml = __innerHtml;
        if (/\[\[.+\]\]/.test(__innerHtml)) {
            __innerHtml.match(/\[\[[^\]\[]+\]\]/gi)?.forEach(_item => {
                let originalCode = _item.replace('[[', '').replace(']]', '');
                finallyHtml = finallyHtml.replace(_item, this.data.val[originalCode])
            })
        }
        return finallyHtml;
    }
    /* 获得标签模板 */
    getTemplate() {
        if (!this.template) {
            this.template = DuoUtils.getDOM(this.entry).innerHTML || '';
        }
    }
    /* 创建虚拟DOM树 */
    createVDOMTree() {
        this.getTemplate();
        this.DuoVDOMTree = (new DuoVDOM).DuoVDOMTree(this.template);
        /* 清空Duo框架根容器的html内容 */
        DuoUtils.getDOM(this.entry).innerHTML = '';
        return this;
    }
    /* 渲染虚拟DOM树到代码片段 */
    createFraments(_VDOMTree) {
        let DOMFramentTree = document.createDocumentFragment(); // 创建DOM代码片段
        _VDOMTree.forEach(_item => {
            const { DuoStr, DuoTag } = _item;
            if (DuoStr) { // 如果该项存在则是字符串
                let tempStrVDOM = document.createTextNode(DuoStr);
                /* 添加到虚拟节点树 */
                DOMFramentTree.appendChild(tempStrVDOM);
            } else if (DuoTag) { // 如果该项存在是Duo框架的虚拟标签
                const { DuoAttributes = [], DuoChildren = [], DuoInnerHTML = null } = _item
                let tempTagVDOM = document.createElement(DuoTag);
                /* 处理属性 */
                if (DuoAttributes?.length > 0) {
                    DuoAttributes.forEach(_attrItem => {
                        const { __duoKey = null, __duoVal = null } = _attrItem;
                        if (__duoKey === 'class') {
                            let classVals = DuoUtils.DuoReplaceDoubelSpace(__duoVal)
                            classVals.split(" ").forEach(_itemClassName => {
                                tempTagVDOM.classList.add(_itemClassName)
                            })
                        } else if (/\$[a-z]+/gi.test(__duoKey)) {

                        } else {
                            __duoVal && __duoKey ? tempTagVDOM.setAttribute(__duoKey, __duoVal) : void (0);
                        }
                    })
                }
                /* 子节点处理 */
                if (DuoChildren?.length > 0) {
                    tempTagVDOM.appendChild(this.createFraments(DuoChildren))
                } else {
                    /(<.+>)*^/gi.test(DuoInnerHTML) ? tempTagVDOM.innerHTML = this.handlerData(DuoInnerHTML) : void (0);
                }
                /* 添加到虚拟DOM片段树 */
                DOMFramentTree.appendChild(tempTagVDOM);
            }

        });
        return DOMFramentTree; // 返回生成好的虚拟DOM片段树
    }
    /* 更新视图 */
    renderView() {
        this.DuoVDOMFraments && DuoUtils.getDOM(this.entry).appendChild(this.DuoVDOMFraments);
    }
    /* 渲染真实DOM */
    renderDOM(_entey) {
        if (DuoUtils.hasDOM(_entey)) {
            if (this.data && !(this.data instanceof DuoActive)) {
                this.data = this.act(this.data,()=>{
                    this.DuoVDOMFraments = this.DuoVDOMTree?.length > 0 ? this.createFraments(this.DuoVDOMTree) : null;
                    this.renderView(); // 更新视图
                })
            }
            this.entry = _entey;
            this.createVDOMTree(); // 创建虚拟DOM树
            this.DuoVDOMFraments = this.DuoVDOMTree?.length > 0 ? this.createFraments(this.DuoVDOMTree) : null;
            this.renderView(); // 更新视图
            //this.handlerDuoObserver(this.data)
        }
        return this;
    }
    /* 抛出错误 */
    thowError(_str = '') {
        throw Error(`[An Error From DUO Frame!]:${_str}`);
    }
    /* 警告 */
    thowWarn(_str = '') {
        console.warn(`[A Warning From DUO Frame!]:${_str}`);
    }
    /* 铎哥框架提示 */
    welcomeMsg(_str = '') {
        console.info('%c' + `[Duo.js]:${_str}`, 'display:inline-block;background-color:pink;color:white;padding:2px;font-size:14px;border:2px solid #eee;border-radius: 15px;font-weight:700;text-shadow:1px 1px 10px rgba(0,0,0,.3);')
    }
    /* 响应绑定 */
    DuoReactiveBind(_data, _key, _val) {
        let that = this;
        Object.defineProperty(_data, _key, {
            set(_newVal) {
                if (_val !== _newVal) {
                    _val = _newVal
                    that.renderView(); // 更新视图
                }
                return _newVal;
            }
        })
    }
    handlerDuoObserver(_data) {
        /* 对象属性不为object(复杂)类型不做处理 */
        // if (!_data || typeof _data !== 'object') {
        //     return _data;
        // }

        // /* 遍历对象或者对象属性 */
        // for (let key in _data) {
        //     this.DuoReactiveBind(_data, key, _data[key])
        //     //递归绑定
        //     this.handlerDuoObserver(_data)
        // }
        // _data = this.act(_data);

    }
    /* ACT */
    act(_d, _c) {
        return new DuoActive(_d, _c)
    }

}

/* Duo响应式 */
class DuoActive {
    constructor(d, c) {
        this.d = d;
        this.c = c;
    }
    updateView() {
        (() => {
            this.c?.();
        })()
    }
    get val() {
        this.updateView();
        return this.d;
    }
}


class DuoVDOM {
    /* 检查一个标签是单标签还是双标签 */
    checkTagType(_tagNameStr) {
        return ['base',
            'br',
            'hr',
            'img',
            'input',
            'col',
            'frame',
            'link',
            'img',
            'param',
            'embed',
            'keygen',
            'area'].includes(_tagNameStr);
    }

    /* 把两个空格转换为一个空格 */
    DuoReplaceDoubelSpace(_str = '') {
        return _str.trim().replace("  ", " ");
    }

    /* 移除HTML注释 */
    DuoRemoveAnnotation(_str = '') {
        return _str.replace(/<\!\-\-.*\-\->/gi, "");
    }

    /* DuoVDOMTree生成器 */
    DuoVDOMTree(_TagStr) {
        let tempArr = this.DuoRemoveAnnotation(_TagStr).split(""); // 分割成单个字符串
        let tempStr = '';
        let finnalVDOMTree = [];
        let tempTagName = '';
        let matchMode = 0; // 匹配模式 0. 字符串 1. 标签名 2. 标签属性 3. innnerHTML
        let finnalTempAttributes = [];
        let that = this;
        tempArr.forEach(_item => {
            tempStr += _item;
            switch (matchMode) {
                case 0: handerStr(); break;
                case 1: handerTagName(); break;
                case 2: handerTagAttributes(); break;
                case 3: handerTagInnerHTML(); break;
            }
            function handerStr() {
                if (_item === '<' && tempStr.length >= 1) {
                    tempStr.slice(0, -1) && finnalVDOMTree.push({ DuoStr: tempStr.slice(0, -1) });
                    matchMode = 1;
                    tempStr = '';
                }
            }
            function handerTagName() {
                finnalTempAttributes = []; // 清空之前的属性
                if (/\s|>|\//.test(_item)) {
                    tempTagName = tempStr.slice(0, -1);
                    if (_item === ' ') { // 如果存在属性
                        matchMode = 2;
                        tempStr = ''

                    } else {
                        if (that.checkTagType(tempTagName)) {
                            /* 如果是单标签没有属性就存储单标签信息 */
                            finnalVDOMTree.push({ DuoTag: tempTagName });
                            /* 跳转到字符串匹配模式 */
                            matchMode = 0;

                        } else {
                            /* 跳转到匹配属性模式 */
                            matchMode = 3;
                        }
                        tempStr = ''; // 清空存储信息

                    }
                }
            }

            function handerTagAttributes() {
                if (/\/|>/.test(_item)) {
                    let tempAttributes = that.DuoReplaceDoubelSpace(tempStr.trim().slice(0, -1));
                    let tempAtrs = tempAttributes.split(" ");
                    tempAtrs.forEach(_atrsItem => {
                        let tempCurrentAttr = _atrsItem.split("=");
                        finnalTempAttributes.push({
                            __duoKey: tempCurrentAttr[0],
                            __duoVal: tempCurrentAttr[1]?.replace(/"|'/g, '') || null
                        })
                    })
                    if (that.checkTagType(tempTagName)) {
                        /* 如果是单标签就存储这个单标签 */
                        finnalVDOMTree.push({ DuoTag: tempTagName, DuoAttributes: finnalTempAttributes });
                        /* 跳转到字符串匹配模式 */
                        matchMode = 0;
                        finnalTempAttributes = []; // 清空标签信息
                    } else {
                        /* 跳转到innerHTML匹配模式 */
                        matchMode = 3;
                    }
                    tempStr = ''; // 清空存储信息
                }


            }
            function handerTagInnerHTML() {
                let passTimes = 0;
                if ((new RegExp(`<${tempTagName}.*>`)).test(tempStr)) {
                    passTimes++;
                }
                if (tempStr.match(new RegExp(`<\/${tempTagName}>`, 'gi')) && tempStr.match(new RegExp(`<\/${tempTagName}>`, 'gi')).length - passTimes === 1) {
                    let innnerHTML = tempStr.slice(0, `</${tempTagName}>`.length * -1);
                    finnalVDOMTree.push({
                        DuoTag: tempTagName,
                        DuoAttributes: finnalTempAttributes,
                        DuoInnerHTML: innnerHTML.length > 0 ? innnerHTML : null,
                        DuoChildren: /<.+>/.test(tempStr) ? that.DuoVDOMTree(innnerHTML) : null
                    });
                    matchMode = 0;
                    tempStr = '';
                }
            }
        })
        return finnalVDOMTree;
    }



}